
import { _decorator, Node, Vec3, SkeletalAnimation, v3, RigidBody2D, v2, CircleCollider2D, Collider2D, ERigidBody2DType, SkinnedMeshRenderer, Material, Contact2DType, IPhysics2DContact, renderer, Vec4, director, Mat4, Texture2D, Color, Camera, UITransform, Prefab, MeshRenderer, ValueType, Quat, quat } from 'cc';
import LevelColler from '../../MainScene/Script/LevelColler';
import Action3dManager, { ActionMngType } from '../../Script/Common/Action3dManager';
import GameData from '../../Script/Common/GameData';
import GlobalData from '../../Script/Common/GlobalData';
import GlobalPool, { customPoolScript } from '../../Script/Common/GlobalPool';
import Loader from '../../Script/Common/Loader';
import GameConfig from '../../Script/GameSpecial/GameConfig';
import { EventType } from '../../Script/GameSpecial/GameEventType';
import { GlobalEnum } from '../../Script/GameSpecial/GlobalEnum';
import AtkBox from './AtkBox';
import { RoleAnimFrameEvent } from './RoleAnimFrameEvent';
const { ccclass, property } = _decorator;

let mat4: Mat4 = new Mat4();

/**角色基类 */
@ccclass('Role')
export class Role extends LevelColler {

    public isPlayer: boolean = false;

    /**************************************************通用流程**************************************************/
    protected initSub() {
        this.initAABB();
        this.initAlive();
        this.initAnim();
        this.initAtkBox();
        this.initAtkScopeNode();
        this.initChuanSong();
        this.initCollCb();
        this.initDisToPlayer();
        this.initHat();
        this.initInvicible();
        this.initMoveSpeed();
        this.initRigidNode();
        this.initRoleScale();
        this.initSkin();
        this.initWeapon();
    }
    protected resetSub() {
        this.resetAABB();
        this.resetAlive();
        this.resetAnim();
        this.resetAtkBox();
        this.resetAtkScopeNode();
        this.resetChuanSong();
        this.resetCollCb();
        this.resetDirtyFlags();
        this.resetDisToPlayer();
        this.resetHat();
        this.resetInvicible();
        this.resetMoveSpeed();
        this.resetRigidNode();
        this.resetRoleScale();
        this.resetSkin();
        this.resetWeapon();
        Action3dManager.getMng(ActionMngType.Level).stopAllActions(this.node);
    }
    protected registAllCustomUpdate() {
        this.registCustomUpdate(GlobalEnum.RoleState.atkReading, this.stepAtkReading);
        // this.registCustomUpdate(GlobalEnum.RoleState.atkEnter, this.stepAtkEnter);
        // this.registCustomUpdate(GlobalEnum.RoleState.atking, this.stepAtking);
        // this.registCustomUpdate(GlobalEnum.RoleState.atkEnd, this.stepAtkEnd);

        this.registCustomUpdate(GlobalEnum.RoleState.move, this.stepMove);
        this.registCustomUpdate(GlobalEnum.RoleState.stand, this.stepStand);
        this.registCustomUpdate(GlobalEnum.RoleState.win, this.stepWin);

    }

    protected enterCustomUpdateState(state: GlobalEnum.RoleState) {
        if (this._customUpdateState != state) {
            this._customUpdateState = state;
            if (!!this.customUpdateMap[state]) {
                this.customStep = this.customUpdateMap[state];
            } else {
                this.customStep = this.stepEmpty;
            }
            switch (state) {
                case GlobalEnum.RoleState.stand: {
                    this.playAnim(GlobalEnum.RoleAnimType.stand);
                    break;
                }
                case GlobalEnum.RoleState.move: {
                    this.playAnim(GlobalEnum.RoleAnimType.move);
                    break;
                }
                case GlobalEnum.RoleState.atkReading: {
                    this.playAnim(GlobalEnum.RoleAnimType.atk, 0);
                    break;
                }
                case GlobalEnum.RoleState.win: {
                    this.playAnim(GlobalEnum.RoleAnimType.win, 0);
                    break;
                }
                case GlobalEnum.RoleState.deadAnimPlaying: {
                    this.playAnim(GlobalEnum.RoleAnimType.dead, 0);
                    break;
                }
                case GlobalEnum.RoleState.jumpInPortal:
                case GlobalEnum.RoleState.jumpOutPortal: {
                    this.playAnim(GlobalEnum.RoleAnimType.stand);
                    break;
                }
            }
        }
    }

    protected setData(data: { p?: Vec3, weaponType?: GlobalEnum.WeaponType, weaponId?: number, skin?: number, hat?: number }) {
        if (undefined !== data.p) {
            this.setPosition(data.p);
        }
        if (undefined !== data.weaponType) {
            this.setWeapon(data.weaponType, data.weaponId);
        }
        if (undefined !== data.skin) {
            this.setSkin(data.skin);
        }
        if (undefined !== data.hat) {
            this.setHat(data.hat);
        }
    }

    /**************************************************对外接口**************************************************/
    /**进入关卡 */
    public enterLevel(data?: any) {
        this.show();
        //设置武器，等级数据等
        if (!!data && undefined !== data.weaponType) {
            this.setWeapon(data.weaponType, data.weaponId);
        }
        if (!!data && undefined !== data.skin) {
            this.setSkin(data.skin);
        }
        if (!!data && undefined !== data.hat) {
            this.setHat(data.hat);
        }
        if (!!data && undefined !== data.invicible) {
            this.enterInvicible(data.invicible);
        } else {
            this.enterInvicible(3);
        }
        this.setRoleScale(GameConfig.GameRule.minScale);
        this.showAtkScopeNode();
        this.enableAtkBox();
        this.enterCustomUpdateState(GlobalEnum.RoleState.stand);
        this.isAlive = true;
    }
    public exitLevel() {
        this.disableRigidNode();
        this.disableAtkBox();
    }

    //移动、面向
    public setEulerAngles(angle: Vec3 | number) {
        let e = 0;
        if (typeof angle === "number") {
            e = angle;
        } else {
            e = angle.y;
        }
        this.targetRadian = e * 0.017453;
        this.faceRadian = this.targetRadian;
        this.node.eulerAngles = v3(0, e, 0);
    }
    /**
     * 设置移动方向
     * @param x 移动方向x分量
     * @param z 移动方向z分量
     */
    public setMoveDir(x: number, z: number) {
        if (!this.canMove()) return;
        let radianY = Math.atan2(-z, x) * 0.5;
        this.targetRadian = radianY * 2;
        this.speed.x = x;
        this.speed.z = z;
        this.speed.normalize().multiplyScalar(this.moveSpeedValue * this.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.speed);
        this.enterCustomUpdateState(GlobalEnum.RoleState.move);
    }
    /**
     * 设置移动方向
     * @param angle 移动方向与X轴夹角，逆时针为正，对应为角色Y轴旋转角度
     */
    public setMoveAngle(angle: number) {
        this.setMoveRadian(angle * 0.017453);
    }
    /**
     * 设置移动方向
     * @param radian 移动方向与X轴夹角弧度
     */
    public setMoveRadian(radian: number) {
        if (!this.canMove()) return;
        if (radian > 6.2831853) {
            radian -= 6.2831853;
        } else if (radian < 0) {
            radian += 6.2831853;
        }
        this.playWalkParticle(radian);
        this.targetRadian = radian;
        let radianY = radian * 0.5;
        this.node.setRotation(0, Math.sin(radianY), 0, Math.cos(radianY));
        let s = this.moveSpeedValue * this.roleScale;
        let sin = Math.sin(radianY * 2);
        let cos = Math.cos(radianY * 2);
        this.speed.x = s * cos;
        this.speed.z = -s * sin;
        this.setDirtyFlags(GlobalEnum.DirtyType.speed);
        this.enterCustomUpdateState(GlobalEnum.RoleState.move);
    }
    public stopMove() {
        this.speed.x = 0;
        this.speed.z = 0;
        this.setDirtyFlags(GlobalEnum.DirtyType.speed);
        this.enterCustomUpdateState(GlobalEnum.RoleState.stand);
    }
    /**上一次产生灰尘效果的时间戳 */
    protected walkParticleTime: number = 0;
    protected playWalkParticle(radian) {
        if (this.customUpdateState == GlobalEnum.RoleState.move) {
            let tr = this.faceRadian;
            if (tr > 6.28) {
                tr -= 6.28;
            } else if (tr < 0) {
                tr += 6.28;
            }
            let s = Math.abs(tr - radian);
            if (s < 1.57) {
                return;
            }
            let t = director.getCurrentTime();
            if (t - this.walkParticleTime < 500) {
                return;
            }
            this.walkParticleTime = t;
        }
        let p = this.node.getPosition();
        this.emit(EventType.LevelEvent.addParticle, {
            n: "WalkParticle",
            p: p,
        });
    }

    /**开始攻击 */
    public startAtk() {
        if (this.canAtk()) {
            this.speed.x = 0;
            this.speed.z = 0;
            this.setDirtyFlags(GlobalEnum.DirtyType.speed);
            this.atkElapsed = 0;
            this.enterCustomUpdateState(GlobalEnum.RoleState.atkReading);
            //播放音效
            if (this.isPlayer || this.disToPlayerSqr < GameConfig.GameRule.enemyAudioScopeSqr) {
                switch (this.weaponType) {
                    // case GlobalEnum.WeaponType.hunter: {
                    //     break;
                    // }
                    case GlobalEnum.WeaponType.katana: {
                        break;
                    }
                    default: {
                        let clip = "atk" + this.weaponType + this.weaponId;
                        this.emit(EventType.Common.AudioEvent.playEffect, GlobalEnum.AudioClip[clip]);
                    }
                }
            }
            //引爆之前的炸弹
            if (this.weaponType == GlobalEnum.WeaponType.trapper) {
                this.emit(EventType.LevelEvent.dropTrapper, this.Id);
            }
        }
    }

    /**被击 */
    public beHit(atkRole: Role) {
        this.isAlive = false;
        Action3dManager.getMng(ActionMngType.Level).stopAllActions(this.node);
    }
    /**成功击中目标 */
    public hitSuccess(target: LevelColler) {
    }

    public getGold() {
        //材质球参数
        this.setMatGetGoldColor();
    }

    public enterInvicible(time: number = 3) {
        this.invicibleTime = time;
        if (time > 0) {
            this._invicible = true;
            this.addScanBox();
        }
    }

    /**跳进下水道 */
    public jumpInPortal(portalPos: Vec3, nextPortalPos: Vec3) {
        // this.stopMove();
        this.endAtkBox();
        this.disableRigidNode();
        this.enterCustomUpdateState(GlobalEnum.RoleState.jumpInPortal);
        this._invicible = true;
        let move = Action3dManager.moveTo(0.5, portalPos);
        let scale = Action3dManager.scaleTo(0.5, 0, 0, 0);
        let spawn = Action3dManager.spawn(move, scale);
        let cb = Action3dManager.callFun(this.onJumpInFinish, this, nextPortalPos);
        let seq = Action3dManager.sequence(spawn, cb);
        Action3dManager.getMng(ActionMngType.Level).runAction(this.node, seq);
        if (!this.isPlayer) {
            this.emit(EventType.LevelEvent.enemyJumpInPortal, this);
        }
        if (this.isPlayer) {
            this.offEvents();
        }
        this.nextPortalPos.set(nextPortalPos);
        this.speed.x = nextPortalPos.x - this.node.position.x;
        this.speed.z = nextPortalPos.z - this.node.position.z;
        this.speed.normalize().multiplyScalar(0.8);
        this.needSync2To3 = false;
        this.canChuanSong = false;
    }
    protected onJumpInFinish(pos: Vec3) {
        // if (this.isPlayer) {
        //     this.emit(EventType.LevelEvent.playerJumpInPortalFinish);
        // } else {
        setTimeout(() => {
            this.jumpOutPortal(pos);
        }, 0);
        // }
    }
    public jumpOutPortal(pos: Vec3) {
        // this.setPosition(pos);
        let move = Action3dManager.moveTo(1, pos);
        let s = this.roleScale;
        let scale = Action3dManager.scaleTo(0.5, s, s, s);
        let cb = Action3dManager.callFun(this.onJumpOutFinish, this);
        let seq = Action3dManager.sequence(move, scale, cb);
        Action3dManager.getMng(ActionMngType.Level).runAction(this.node, seq);
        this.enterCustomUpdateState(GlobalEnum.RoleState.jumpOutPortal);
    }
    protected onJumpOutFinish() {
        this.enableRigidNode();
        if (this.invicibleTime < 0) {
            this._invicible = false;
        }
        this.enterCustomUpdateState(GlobalEnum.RoleState.stand);
        if (!this.isPlayer) {
            this.emit(EventType.LevelEvent.enemyJumpOutPortalFinish, this);
        }
        if (this.isPlayer) {
            this.onEvents();
        }
        this.needSync2To3 = true;
        this.canChuanSong = true;
    }


    public changeSkin(data: { weaponType?: GlobalEnum.WeaponType, weaponId?: number, skin?: number }) {
        if (!!data && undefined !== data.skin) {
            this.setSkin(data.skin);
        }
        if (!!data && undefined !== data.weaponType) {
            this.setWeapon(data.weaponType, data.weaponId);
            this.showAtkScopeNode();
        }
        // if (!!data && undefined !== data.hat) {
        //     this.setHat(data.hat);
        // }
    }


    /**************************************************管理对象**************************************************/
    //#region 人物模型
    @property(SkinnedMeshRenderer)
    protected skin: SkinnedMeshRenderer = null;
    protected mat: Material = null;
    protected pass: renderer.Pass = null;
    protected handleColorTransform: number;
    protected colorTransform: Vec4;
    protected getGoldTime: number = 0;
    public skinId: number = 0;
    protected initSkin() {
        if (!this.skin) {
            this.skin = this.node.getChildByName("role").getComponentInChildren(SkinnedMeshRenderer);
        }
        this.mat = this.skin.getMaterialInstance(0);
        this.pass = this.mat.passes[0];
        this.handleColorTransform = this.pass.getHandle("colorTransform");
        this.colorTransform = new Vec4();
        this.pass.getUniform(this.handleColorTransform, this.colorTransform);
    }
    protected resetSkin() {
        this.colorTransform.x = 0;
        this.colorTransform.y = 1;
        this.applyMatUniform();
    }
    protected setSkin(id) {
        //加载对应贴图赋值给材质球
        this.skinId = id;
        Loader.loadBundleRes("Role", "PlayerSkin2/skin" + this.skinId, (res) => {
            let t = new Texture2D();
            t.image = res;
            this.mat.setProperty("mainTexture", t);
        });
    }
    protected setMatGetGoldColor() {
        this.getGoldTime = 0.15;
        this.colorTransform.x = 1;
        this.applyMatUniform();
    }
    protected applyMatUniform() {
        this.pass.setUniform(this.handleColorTransform, this.colorTransform);
    }
    protected updateMatUniform(dt: number) {
        if (this.getGoldTime <= 0) return;
        this.getGoldTime -= dt;
        if (this.getGoldTime <= 0) {
            this.getGoldTime = 0;
        }
        this.colorTransform.x = this.getGoldTime * 10;
        this.applyMatUniform();
    }
    //#endregion

    //#region 无敌状态
    protected scanBox: Node = null;
    protected _invicible: boolean = false;
    public get invicible() { return this._invicible; }
    protected invicibleTime: number = 0;
    protected scanBoxQuat: Quat = null;
    protected scanBoxRadianY: number = 0;
    protected initInvicible() {
        this._invicible = false;
        this.invicibleTime = 0;
        this.scanBoxQuat = quat(0, 0, 0, 1);
    }
    protected resetInvicible() {
        this.removeScanBox();
        this._invicible = false;
        this.invicibleTime = 0;
        this.scanBoxQuat.y = 0;
        this.scanBoxQuat.w = 1;
        this.scanBoxRadianY = 0;
    }
    protected removeScanBox() {
        if (!!this.scanBox) {
            GlobalPool.put(this.scanBox);
            this.scanBox = null;
        }
    }
    protected addScanBox() {
        let node = GlobalPool.get("ScanBox");
        node.setPosition(this.node.position);
        node.setScale(this.roleScale, this.roleScale, this.roleScale);
        this.scanBox = node;
        this.scanBox.setRotation(this.scanBoxQuat);
        this.emit(EventType.LevelEvent.addScanBox, this.scanBox);
    }
    protected updateInvicible(dt: number) {
        if (this.invicibleTime < 0) return;
        this.invicibleTime -= dt;
        if (this.invicibleTime < 0) {
            this.removeScanBox();
            this._invicible = false;
            return;
        }
        if (!!this.scanBox) {
            this.scanBox.setPosition(this.node.position);
            this.scanBoxRadianY += dt * 0.78;
            if (this.scanBoxRadianY >= 3.1415926) {
                this.scanBoxRadianY = 0;
            }
            this.scanBoxQuat.y = Math.sin(this.scanBoxRadianY);
            this.scanBoxQuat.w = Math.cos(this.scanBoxRadianY);
            this.scanBox.setRotation(this.scanBoxQuat);
        }
    }
    //#endregion

    //#region 动画组件
    /**动画组件 */
    protected anim: SkeletalAnimation = null;
    /**当前播放的动画名称 */
    protected curAnimClip: string;
    /**动画播放完成回调 */
    protected animFinishCb: Function = null;
    protected initAnim() {
        if (!this.anim) {
            this.anim = this.node.getComponentInChildren(SkeletalAnimation);
        }
        let js = this.anim.node.getComponent(RoleAnimFrameEvent);
        if (!js) {
            js = this.anim.node.addComponent(RoleAnimFrameEvent);
        }
        js.setRole(this);
        this.anim.on("finished", this.onAnimFinish, this);
        // this.anim.on("lastframe", this.onAnimFinish, this);
    }
    protected resetAnim() {

    }
    protected playAnim(anim: string, crossDuration: number = 0.1, cb?: Function) {
        this.curAnimClip = anim;
        let clip = this.getAnimClipName(anim);
        this.anim.play(clip);
        // if (crossDuration <= 0) {
        // } else {
        //     this.anim.crossFade(clip, crossDuration);
        // }
        // if (this.isPlayer && anim == GlobalEnum.RoleAnimType.dead) {
        //     this.anim.getState(clip).speed = 5;
        // } else {
        // }
        switch (anim) {
            case GlobalEnum.RoleAnimType.atk: {
                // this.anim.getState(clip).speed = 2;
                break;
            }
            case GlobalEnum.RoleAnimType.move: {
                break;
            }
            default: {
                break;
            }
        }
        // this.anim.getState(clip).speed = 2;
        this.animFinishCb = cb;
        // if (this.weaponType == GlobalEnum.WeaponType.gun) {
        // if (anim == GlobalEnum.RoleAnimType.atk || anim == GlobalEnum.RoleAnimType.stand) {
        //     this.anim.node.eulerAngles = v3(0, 50, 0);
        // } else {
        // this.anim.node.eulerAngles = v3(0, 90, 0);
        // }
        // }
    }
    protected getAnimClipName(anim: string) {
        switch (anim) {
            case GlobalEnum.RoleAnimType.dead:
            case GlobalEnum.RoleAnimType.win: {
                return anim;
            }
            default: {
                if (this.weaponType == GlobalEnum.WeaponType.none) {
                    return "Model|" + GlobalEnum.WeaponType.knife + "_" + anim;
                }
                return "Model|" + this.weaponType + "_" + anim;
            }
        }
    }
    protected onAnimFinish() {
        let cb = this.animFinishCb;
        this.animFinishCb = null;
        switch (this.curAnimClip) {
            case GlobalEnum.RoleAnimType.atk: {
                this.enterCustomUpdateState(GlobalEnum.RoleState.stand);
                // if (this.leftWeapon) {
                //     this.leftWeapon.atkFinish();
                // }
                // this.rightWeapon.atkFinish();
                break;
            }
            case GlobalEnum.RoleAnimType.win: {
                break;
            }
            case GlobalEnum.RoleAnimType.dead: {
                this.enterCustomUpdateState(GlobalEnum.RoleState.deadAnimFinish);
                if (this.node.name == "Player") {
                    this.emit(EventType.LevelEvent.playerDeadAnimFinished);
                }
                break;
            }
        }
        if (!!cb) {
            cb();
        }
    }
    public animAtkStart() {
        this.startAtkBox();
        this.processWeaponStartAtking();
    }
    public animAtkEnd() {
        this.endAtkBox();
    }

    public animPlayAudio(clip?: string) {
        if (!clip) {
            clip = "";
            switch (this.weaponType) {
                case GlobalEnum.WeaponType.captain: {
                    break;
                }
            }
        }
        if (!!clip) {
            this.emit(EventType.Common.AudioEvent.playEffect, clip);
        }
    }
    public animPlayEffect() {

    }
    public animShake() {

    }
    //#endregion

    //#region 碰撞体替身
    /**在2D物理世界生成一个碰撞体替身 */
    protected createRigidNode() {
        if (!!this.rigidNode) return;
        //碰撞体节点
        let node = new Node(GlobalEnum.RigidNode.role);
        this.rigidNode = node;
        //刚体组件
        let rigid = node.addComponent(RigidBody2D);
        let group = this.isPlayer ? GlobalEnum.RigidGroup.player : GlobalEnum.RigidGroup.enmey;
        rigid.group = group;
        rigid.enabledContactListener = true;
        rigid.bullet = false;
        rigid.type = ERigidBody2DType.Dynamic;
        rigid.allowSleep = false;
        rigid.gravityScale = 0;
        rigid.linearDamping = 0;
        rigid.angularDamping = 0;
        rigid.linearVelocity = v2(0, 0);
        rigid.angularVelocity = 0;
        rigid.fixedRotation = true;
        rigid.awakeOnLoad = true;
        this.rigid = rigid;
        //碰撞体形状
        let collider = node.addComponent(CircleCollider2D);
        collider.tag = 0;
        collider.group = group;
        collider.density = this.isPlayer ? 3 : 1;
        collider.sensor = false;
        collider.friction = 0;
        collider.restitution = 0;
        collider.offset = v2(0, 0);
        collider.radius = GameConfig.GameRule.roleRadius * GameConfig.GameRule.rate3to2 * this.roleScale;

        if (!this.isPlayer) {
            collider.on(Contact2DType.POST_SOLVE, this.onConcatBegin, this);
        }
        this.collider2d = collider;
    }
    /**激活碰撞体替身 */
    public enableRigidNode() {
        this.createRigidNode();
        this.resetRigidNode();
        this.emit(EventType.LevelEvent.addRigidNode, this.rigidNode);
        let rate = GameConfig.GameRule.rate3to2;
        this.rigidNode.setPosition(this.node.position.x * rate, -this.node.position.z * rate, 0);
        this.rigidNode.angle = this.node.eulerAngles.y;
        this.collider2d.radius = GameConfig.GameRule.roleRadius * GameConfig.GameRule.rate3to2 * this.roleScale;

    }
    protected onConcatBegin(self: Collider2D, other: Collider2D, concat: IPhysics2DContact) {
        for (let i = this.collCb.length - 1; i >= 0; --i) {
            this.collCb[i].cb.call(this.collCb[i].target, self, other, concat);
        }
    }
    protected collCb: { cb: Function, target: any }[] = [];
    protected needSync2To3: boolean = true;
    protected initCollCb() {
        this.collCb = [];
        this.needSync2To3 = true;
    }
    protected resetCollCb() {
        this.collCb = [];
        this.needSync2To3 = true;
    }
    public onCollCb(cb: Function, target: any) {
        this.collCb.push({ cb: cb, target: target });
    }
    public offCollCb(cb: Function, target: any) {
        for (let i = this.collCb.length - 1; i >= 0; --i) {
            if (this.collCb[i].cb == cb && this.collCb[i].target == target) {
                this.collCb.splice(i, 1);
                break;
            }
        }
    }
    /**将3D节点信息同步到2D碰撞体 */
    public syncModelToRigid() {
        if (this.getDirtyFlags(GlobalEnum.DirtyType.roleScale)) {
            this.collider2d.radius = GameConfig.GameRule.roleRadius * GameConfig.GameRule.rate3to2 * this.roleScale;
            this.collider2d.apply();
            this.clearDirtyFlags(GlobalEnum.DirtyType.roleScale);
        }
        if (this.getDirtyFlags(GlobalEnum.DirtyType.speed)) {
            this.clearDirtyFlags(GlobalEnum.DirtyType.speed);
            this.cacheLinearVelocity.x = this.speed.x * GameConfig.GameRule.rate3to2;
            this.cacheLinearVelocity.y = -this.speed.z * GameConfig.GameRule.rate3to2;
            this.rigid.linearVelocity = this.cacheLinearVelocity;
        }
    }
    /**将碰撞体信息同步到3D节点 */
    public syncRigidToModel() {
        if (!this.needSync2To3) return;
        //坐标
        let p = this.rigidNode.position;
        let r = GameConfig.GameRule.rate2to3;
        this.prePos.x = p.x * r;
        this.prePos.z = -p.y * r;
        this.node.setPosition(this.prePos);
        this.setDirtyFlags(GlobalEnum.DirtyType.pos);
        this.setDirtyFlags(GlobalEnum.DirtyType.aabb);
        this.updateDisToPlayer();
    }
    //#endregion

    //#region 武器
    /**左手节点（武器要挂载的节点） */
    @property(Node)
    protected leftHand: Node = null;
    /**右手节点 */
    @property(Node)
    protected rightHand: Node = null;
    /**左手握持的武器 */
    // protected leftWeapon: Weapon = null;
    /**右手握持的武器 */
    // protected rightWeapon: Weapon = null;
    /**当前使用的武器类型 */
    public weaponType: GlobalEnum.WeaponType = GlobalEnum.WeaponType.none;
    /**当前使用的武器在该类型下的id，0表示没有使用武器 */
    public weaponId: number = 0;
    protected initWeapon() { }
    protected resetWeapon() {
        this.removeWeapon();
    }
    /**
     * 设置角色使用的武器
     * @param type 武器类型
     * @param id 该类型下的武器id
     */
    protected setWeapon(type: GlobalEnum.WeaponType, id: number) {
        this.removeWeapon();
        this.weaponType = type;
        this.weaponId = id;
        //加载武器模型
        let str = this.weaponType + this.weaponId;
        if (this.weaponType == GlobalEnum.WeaponType.trapper) {
            str += this.isPlayer ? "player" : "enemy";
        }
        let node = GlobalPool.get(str);
        if (!!node) {
            setTimeout(() => {
                this.addWeapon(node);
            }, 0);
        } else {
            Loader.loadBundle("Weapon", () => {
                Loader.loadBundleRes("Weapon", "Prefab/" + str, (res) => {
                    GlobalPool.createPool(str, res, str);
                    let node = GlobalPool.get(str);
                    this.addWeapon(node);
                });
            }, false, false);
        }
        //播放对应动画
        if (!!this.curAnimClip) {
            let cb = this.animFinishCb;
            this.playAnim(this.curAnimClip, 0, cb);
        }
        //更新攻击范围
        this.updateAtkScope();
    }
    /**添加武器节点 */
    protected addWeapon(node: Node) {
        switch (this.weaponType) {
            // case GlobalEnum.WeaponType.claw: {
            //     this.leftHand.addChild(node);
            //     node.setPosition(0.003, 0.003, 0.005);
            //     node.eulerAngles = v3(9.877, -259.844, 231.35);
            //     let node2 = GlobalPool.get(this.weaponType + this.weaponId);
            //     this.rightHand.addChild(node2);
            //     node2.setPosition(-0.005, 0.002, 0.005);
            //     node2.eulerAngles = v3(34.532, -114.508, 107.723);
            //     break;
            // }
            case GlobalEnum.WeaponType.trapper: {
                let s = 1;
                node.setScale(s, s, s);
                node.setPosition(0, 0, -0.007);
                node.eulerAngles = v3();
                this.rightHand.addChild(node);
                node[customPoolScript].offEvents();
                break;
            }
            default: {
                this.rightHand.addChild(node);
                break;
            }
        }
    }
    /**移除武器节点 */
    protected removeWeapon() {
        GlobalPool.putAllChildren(this.leftHand);
        GlobalPool.putAllChildren(this.rightHand);
        // this.leftWeapon = null;
        // this.rightWeapon = null;
        this.weaponType = GlobalEnum.WeaponType.none;
        this.weaponId = 0;
    }
    protected updateWeapon(dt: number) {
        // if (this.leftWeapon) {
        //     this.leftWeapon.customUpdate(dt);
        // }
        // if (this.rightWeapon) {
        //     this.rightWeapon.customUpdate(dt);
        // }
    }
    //#endregion

    //#region 攻击功能
    protected canAtk() {
        return this._customUpdateState == GlobalEnum.RoleState.stand
            || this._customUpdateState == GlobalEnum.RoleState.move;
    }
    //#endregion

    //#region 攻击框
    protected atkScopeType: GlobalEnum.AtkScopeType;
    protected atkFan: { radius: number, halfRadian: number };
    protected atkRect: { halfWidth: number, length: number };
    /**攻击范围半径 */
    protected _atkRadius: number = 0;
    public get atkRadius() {
        if (!this._atkRadius || this.getDirtyFlags(GlobalEnum.DirtyType.roleScale)) {
            if (this.atkScopeType === GlobalEnum.AtkScopeType.fan) {
                this._atkRadius = this.atkFan.radius * this.roleScale;
            } else {
                this._atkRadius = this.atkRect.length * this.roleScale;
            }
        }
        return this._atkRadius;
    }
    protected _atkRadiusSqr: number = 0;
    public get atkRadiusSqr() {
        if (!this._atkRadius || this.getDirtyFlags(GlobalEnum.DirtyType.roleScale)) {
            if (this.atkScopeType === GlobalEnum.AtkScopeType.fan) {
                this._atkRadiusSqr = this.atkFan.radius * this.roleScale;
            } else {
                this._atkRadiusSqr = this.atkRect.length * this.roleScale;
            }
            this._atkRadiusSqr = this._atkRadiusSqr * this._atkRadiusSqr + 1;
        }
        return this._atkRadiusSqr;
    }
    public atkBox: AtkBox = null;
    protected initAtkBox() {
        this.atkScopeType = GlobalEnum.AtkScopeType.rect;
        this.atkFan = {
            radius: 1,
            halfRadian: 1,
        };
        this.atkRect = {
            halfWidth: 1,
            length: 1,
        };
        this.atkBox = new AtkBox();
        this.atkBox.init();
        this._atkRadius = 0;
        this._atkRadiusSqr = 0;
    }
    protected resetAtkBox() {
        this.atkBox.reset();
        this._atkRadius = 0;
        this._atkRadiusSqr = 0;
    }
    protected enableAtkBox() {
        if (this.weaponType == GlobalEnum.WeaponType.trapper) return;
        this.emit(EventType.LevelEvent.addAtkBox, this.atkBox);
    }
    protected disableAtkBox() {
        this.emit(EventType.LevelEvent.removeAtkBox, this.atkBox);
    }
    //根据武器类型确定攻击范围
    protected updateAtkScope() {
        if (this.weaponType == GlobalEnum.WeaponType.none) {
            return;
        }
        let data = GameData.getData(GlobalEnum.GameDataType.WeaponAtkData, this.weaponType);
        if (!data) {
            return;
        }
        this.atkScopeType = data.atkScope.type;
        switch (data.atkScope.type) {
            case GlobalEnum.AtkScopeType.fan: {
                this.atkFan.halfRadian = data.atkScope.halfRadian;
                this.atkFan.radius = data.atkScope.radius;
                break;
            }
            case GlobalEnum.AtkScopeType.rect: {
                this.atkRect.halfWidth = data.atkScope.halfWidth;
                this.atkRect.length = data.atkScope.length;
                break;
            }
        }
    }
    protected startAtkBox() {
        if (this.weaponType == GlobalEnum.WeaponType.trapper) return;
        this.atkBox.visible = true;
        switch (this.atkScopeType) {
            case GlobalEnum.AtkScopeType.fan: {
                this.atkBox.setScope({
                    atkRole: this,
                    type: this.atkScopeType,
                    radian: this.faceRadian,
                    radius: this.atkFan.radius * this.roleScale,
                    halfRadianScope: this.atkFan.halfRadian,
                });
                break;
            }
            case GlobalEnum.AtkScopeType.rect: {
                this.atkBox.setScope({
                    atkRole: this,
                    type: this.atkScopeType,
                    radian: this.faceRadian,
                    halfWidth: this.atkRect.halfWidth * this.roleScale,
                    length: this.atkRect.length * this.roleScale,
                });
                break;
            }
        }
    }
    protected endAtkBox() {
        this.atkBox.visible = false;
    }
    //#endregion

    //#region 攻击范围提示节点
    protected atkScopeNode: Node = null;
    protected initAtkScopeNode() {

    }
    protected resetAtkScopeNode() {
        this.hideAtkScopeNode();
    }
    protected showAtkScopeNode() {
        this.hideAtkScopeNode();
        if (this.weaponType == GlobalEnum.WeaponType.trapper) {
            this.showAtkScopeTrapper();
            return;
        }
        let js;
        switch (this.atkScopeType) {
            case GlobalEnum.AtkScopeType.rect: {
                let node = GlobalPool.get("AtkScopeRect");
                js = node[customPoolScript];
                js.setSize(this.atkRect.halfWidth, this.atkRect.length);
                this.atkScopeNode = node;
                this.node.addChild(node);
                break;
            }
            case GlobalEnum.AtkScopeType.fan: {
                //根据武器类型选择大扇形/小扇形
                let str = "AtkScopeFan";
                let node = GlobalPool.get(str);
                js = node[customPoolScript];
                js.setHalfRadian(this.atkFan.halfRadian);
                js.setRadius(this.atkFan.radius);
                this.atkScopeNode = node;
                this.node.addChild(node);
                break;
            }
        }
        //根据角色皮肤设置颜色
        let color;
        if (this.skinId != 0) {
            let c = GameData.getData(GlobalEnum.GameDataType.GoodsData).skin[this.skinId].color;
            color = new Color(c);
        } else {
            let c = GameData.getData(GlobalEnum.GameDataType.GoodsData).skin[1].color;
            color = new Color(c);
        }
        js.setColor(color);
    }
    protected showAtkScopeTrapper() {
        let node = GlobalPool.get("AtkScopeTrapper");
        this.atkScopeNode = node;
        this.node.addChild(node);
        let js = node[customPoolScript];
        let color;
        if (this.skinId != 0) {
            let c = GameData.getData(GlobalEnum.GameDataType.GoodsData).skin[this.skinId].color;
            color = new Color(c);
        } else {
            let c = GameData.getData(GlobalEnum.GameDataType.GoodsData).skin[1].color;
            color = new Color(c);
        }
        js.setColor(color);
        this.updateAtkScopeTrapper(); 
    }
    protected updateAtkScopeTrapper() {
        if (this.weaponType !== GlobalEnum.WeaponType.trapper) return;
        let posArr = this.getTrapperPosArr();
        this.atkScopeNode[customPoolScript].setAtkPos(posArr);
        this.atkScopeNode[customPoolScript].setAtkScale(this.roleScale);
    }
    protected getTrapperPosArr() {
        let s = new Vec3(0, 0, 0);
        let r = 0;
        let spd = this.roleScale * 5;
        s.x = Math.cos(r) * spd * 0.7;
        s.z = -Math.sin(r) * spd * 0.7;

        let h = this.roleScale;
        let t = 2 * h / GameConfig.GameRule.trapperGravity;
        t = Math.sqrt(t);
        let p1 = v3();
        p1.x = s.x * t;
        p1.y = 0.1;
        p1.z = s.z * t;
        let posArr = [];
        posArr.push(p1);

        r = 0.3;
        s.x = Math.cos(r) * spd;
        s.z = -Math.sin(r) * spd;

        let p2 = v3(p1);
        p2.x = s.x * t;
        p2.z = s.z * t;
        posArr.push(p2);

        r = -0.3;
        s.x = Math.cos(r) * spd;
        s.z = -Math.sin(r) * spd;
        let p3 = v3(p1);
        p3.x = s.x * t;
        p3.z = s.z * t;
        posArr.push(p3);
        return posArr;
    }

    protected hideAtkScopeNode() {
        if (!!this.atkScopeNode) {
            GlobalPool.put(this.atkScopeNode);
            this.atkScopeNode = null;
        }
    }
    //#endregion

    //#region 与玩家的距离
    /**角色与玩家距离的平方 */
    public disToPlayerSqr: number = 0;
    protected initDisToPlayer() {
        this.disToPlayerSqr = 0;
    }
    protected resetDisToPlayer() {
        this.disToPlayerSqr = 0;
    }
    protected updateDisToPlayer() {
        if (this.isPlayer) return;
        let player = GlobalData.get(GlobalEnum.myGlobalDataType.player);
        if (!player) {
            this.disToPlayerSqr = 0;
            return;
        }
        let x = this.node.position.x - player.node.position.x;
        let z = this.node.position.z - player.node.position.z;
        this.disToPlayerSqr = x * x + z * z;
    }
    //#endregion

    //#region 饰品
    @property(Node)
    protected hatLayer: Node = null;
    protected initHat() { }
    protected resetHat() {
        GlobalPool.putAllChildren(this.hatLayer);
    }
    protected setHat(id: number) {
        this.resetHat();
        if (id == 0) {
            return;
        }
        let node = GlobalPool.get("hat" + id);
        if (!!node) {
            this.hatLayer.addChild(node);
        } else {
            Loader.loadBundle("Hat", () => {
                Loader.loadBundleRes("Hat", "Prefab/hat" + id, (res) => {
                    GlobalPool.createPool("hat" + id, res, null);
                    let hat = GlobalPool.get("hat" + id);
                    this.hatLayer.addChild(hat);
                    // Loader.loadBundleRes("Hat", "Textures/hat" + id, (res) => {
                    //     let mat = hat.getComponent(MeshRenderer).getMaterialInstance(0);
                    //     let t = new Texture2D();
                    //     t.image = res;
                    //     mat.setProperty("mainTexture", t);
                    // });
                }, Prefab, false);
            }, false, false);
        }
    }
    //#endregion

    /**************************************************属性数据**************************************************/
    //#region 移动
    /**移动速度大小 */
    protected moveSpeedValue: number = 0.08;
    /**实际的速度矢量 */
    public speed: Vec3;
    /**缓存当前帧位置 */
    protected cachePos: Vec3;
    /**上一帧的位置 */
    protected prePos: Vec3;
    /**角色朝向与X轴夹角弧度 */
    public faceRadian: number = 0;
    protected _targetRadian: number = 0;
    /**移动时要转向的目标弧度 */
    protected get targetRadian(): number { return this._targetRadian; }
    protected set targetRadian(v) {
        this._targetRadian = v;
        let pi = Math.PI;
        if (this._targetRadian < 0) {
            this._targetRadian += pi * 2;
        }
        if (this.faceRadian > pi * 2) {
            this.faceRadian -= pi * 2;
        } else if (this.faceRadian < 0) {
            this.faceRadian += pi * 2;
        }
        let s = this._targetRadian - this.faceRadian;
        if (s > pi) {
            this.trunLeft = false;
            this.faceRadian += pi * 2;
        } else if (s > 0) {
            this.trunLeft = true;
        } else if (s < -pi) {
            this.trunLeft = true;
            this._targetRadian += pi * 2;
        } else if (s < 0) {
            this.trunLeft = false;
        }

    }
    /**是否要向左转（逆时针） */
    protected trunLeft: boolean = false;
    protected initMoveSpeed() {
        this.speed = new Vec3(0, 0, 0);
        this.cachePos = new Vec3();
        this.prePos = new Vec3();
        this.faceRadian = 0;
        this._targetRadian = 0;
        this.setDirtyFlags(GlobalEnum.DirtyType.speed);
    }
    protected resetMoveSpeed() {
        this.speed.x = this.speed.y = this.speed.z = 0;
        this.faceRadian = 0;
        this._targetRadian = 0;
        this.setDirtyFlags(GlobalEnum.DirtyType.speed);
    }
    protected setSpeedValue(v) {
        if (v == this.moveSpeedValue || v < 0) return;
        this.moveSpeedValue = v;
        this.speed.normalize().multiplyScalar(this.moveSpeedValue * this.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.speed);
    }
    protected canMove(): boolean {
        return this._customUpdateState == GlobalEnum.RoleState.stand
            || this._customUpdateState == GlobalEnum.RoleState.move;
    }
    //#endregion

    //#region 大小变化
    /**角色身体大小 */
    public roleScale: number = GameConfig.GameRule.minScale;
    protected initRoleScale() {
        this.roleScale = GameConfig.GameRule.minScale;
        this.node.setScale(this.roleScale, this.roleScale, this.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.aabb);
    }
    protected resetRoleScale() {
        this.roleScale = GameConfig.GameRule.minScale;
        this.node.setScale(this.roleScale, this.roleScale, this.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.aabb);
        Action3dManager.getMng(ActionMngType.Level).stopAllActions(this.node);
    }
    public setRoleScale(s: number) {
        if (this.roleScale == s) return;
        Action3dManager.getMng(ActionMngType.Level).stopAllActions(this.node);
        this.roleScale = s;
        this.node.setScale(this.roleScale, this.roleScale, this.roleScale);
        if (!!this.scanBox) {
            this.scanBox.node.setScale(this.roleScale, this.roleScale, this.roleScale);
        }
        this.setDirtyFlags(GlobalEnum.DirtyType.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.aabb);
        this.updateAtkScopeTrapper();
    }
    /**升级变大 */
    protected growUpRoleScale(target?: number) {
        if (!!target) {
            this.roleScale = target;
        } else {
            this.roleScale += GameConfig.GameRule.scaleStep;
        }
        this.setDirtyFlags(GlobalEnum.DirtyType.roleScale);
        this.setDirtyFlags(GlobalEnum.DirtyType.aabb);
        //模型放大
        let s = this.roleScale;
        let scale = Action3dManager.scaleTo(0.2, s, s, s);
        Action3dManager.getMng(ActionMngType.Level).runAction(this.node, scale);
        this.updateAtkScopeTrapper();
    }
    //#endregion

    //#region 存活状态
    public isAlive: boolean = true;
    protected initAlive() {
        // this.isAlive = true;
    }
    protected resetAlive() {
        // this.isAlive = true;
    }
    //#endregion

    //#region 碰撞范围：用于自行检测碰撞的范围
    /**更新碰撞包围盒 */
    protected processDirty() {
        if (this.aabbDirty) {
            this.aabbDirty = false;

            let s = this.roleScale;
            let p = this.node.position;
            this._aabb.xMin = this.minVert.x * s + p.x;
            this._aabb.xMax = this.maxVert.x * s + p.x;
            this._aabb.xScope = (this._aabb.xMax - this._aabb.xMin) * 0.5;

            this._aabb.yMin = this.minVert.y * s + p.y;
            this._aabb.yMax = this.maxVert.y * s + p.y;
            this._aabb.yScope = this._aabb.yMax - this._aabb.yMin;

            this._aabb.zMin = this.minVert.z * s + p.z;
            this._aabb.zMax = this.maxVert.z * s + p.z;
            this._aabb.zScope = (this._aabb.zMax - this._aabb.zMin) * 0.5;

            this._aabb.xCenter = this._aabb.xMin + this._aabb.xScope;
            this._aabb.yCenter = this._aabb.yMin + this._aabb.yScope * 0.5;
            this._aabb.zCenter = this._aabb.zMin + this._aabb.zScope;

            this._center.x = this._aabb.xCenter;
            this._center.y = this._aabb.yCenter;
            this._center.z = this._aabb.zCenter;

        }
    }
    //#endregion

    //#region 传送状态
    protected canChuanSong: boolean = true;
    protected initChuanSong() {
        this.canChuanSong = true;
    }
    protected resetChuanSong() {
        this.canChuanSong = true;
    }
    //#endregion

    /**************************************************事件回调**************************************************/


    /**************************************************运行状态**************************************************/
    /**站立状态 */
    protected stepStand(dt: number) {
        this.updateWeapon(dt);
        this.updateMatUniform(dt);
        this.updateInvicible(dt);
    }
    /**移动 */
    protected stepMove(dt: number) {
        //转向
        if (this.faceRadian !== this.targetRadian) {
            let step = Math.PI * dt * 3;
            if (step > Math.abs(this.targetRadian - this.faceRadian)) {
                this.faceRadian = this.targetRadian;
            } else {
                if (!this.trunLeft) {
                    step = -step;
                }
                this.faceRadian += step;
            }
            let r = this.faceRadian * 0.5;
            this.node.setRotation(0, Math.sin(r), 0, Math.cos(r));
        }
        this.updateWeapon(dt);
        this.updateInvicible(dt);
        this.updateMatUniform(dt);
    }
    /**攻击动作播放累计时长 */
    protected atkElapsed: number = 0;
    /**攻击：预备动作 */
    protected stepAtkReading(dt: number) {
        this.updateInvicible(dt);
        this.updateMatUniform(dt);
    }

    /**处理武器开始攻击判定时的效果:特效，音效等 */
    protected processWeaponStartAtking() {
        //特效
        switch (this.weaponType) {
            case GlobalEnum.WeaponType.katana: {
                //音效
                let clip = "atk" + this.weaponType + this.weaponId;
                this.emit(EventType.Common.AudioEvent.playEffect, GlobalEnum.AudioClip[clip]);
                break;
            }
            //钝器：震屏+冲击波+手机震动
            case GlobalEnum.WeaponType.captain: {
                if (this.isPlayer) {
                    // this.emit(EventType.LevelEvent.shakeScreen, { radius: 0.3, duration: 0.1 });
                    GlobalData.get(GlobalEnum.Common.GlobalDataType.levelCamera).shock({ duration: 0.1, offset: v3(0, 0.3, 0) });
                }
                let p: Vec3 = v3(2.44, 0, 0);
                this.node.getWorldMatrix(mat4);
                Vec3.transformMat4(p, p, mat4);
                p.y += 0.1;
                this.emit(EventType.LevelEvent.addParticle, {
                    n: "ChongJiBo",
                    p: p,
                    s: this.roleScale,
                });
                this.emit(EventType.Common.SDKEvent.vibrateShort);
                break;
            }
            //枪：火花
            case GlobalEnum.WeaponType.gun: {
                //火花
                let p: Vec3 = v3(1.178, 1.717, 0.198);
                this.node.getWorldMatrix(mat4);
                Vec3.transformMat4(p, p, mat4);
                // this.emit(EventType.LevelEvent.addBoomEffect, {
                //     p: p,
                //     s: this.roleScale,
                // });
                this.emit(EventType.LevelEvent.addParticle, {
                    n: "BoomParticle",
                    p: p,
                    s: this.roleScale * 0.5,
                });
                break;
            }
            //炮：火花，震屏，
            case GlobalEnum.WeaponType.hunter: {
                if (this.isPlayer) {
                    // this.emit(EventType.LevelEvent.shakeScreen);
                    let r = 0.3;
                    let p = v3();
                    p.x = Math.cos(this.faceRadian) * r;
                    p.z = -Math.sin(this.faceRadian) * r;
                    GlobalData.get(GlobalEnum.Common.GlobalDataType.levelCamera).shock({ duration: 0.1, offset: p });
                }
                //火花
                let p: Vec3 = v3(0.96, 1.32, 0.31);
                this.node.getWorldMatrix(mat4);
                Vec3.transformMat4(p, p, mat4);
                // this.emit(EventType.LevelEvent.addParticle, {
                //     n: "HuoHua",
                //     p: p,
                //     s: this.roleScale * 0.8,
                //     // radian: this.faceRadian + 1.57,
                // });
                this.emit(EventType.LevelEvent.addBoomEffect, {
                    p: p,
                    s: this.roleScale,
                });
                if (this.weaponId != 4) {
                    this.emit(EventType.LevelEvent.addParticle, {
                        n: "BoomParticle",
                        p: p,
                        s: this.roleScale,
                    });
                }
                //音效
                // let clip = "atk" + this.weaponType + this.weaponId;
                // this.emit(EventType.Common.AudioEvent.playEffect, GlobalEnum.AudioClip[clip]);
                break;
            }
            //炸弹：丢出炸弹
            case GlobalEnum.WeaponType.trapper: {
                let s = new Vec3(0, 0, 0);
                let r = this.faceRadian;
                let spd = this.roleScale * 5;
                s.x = Math.cos(r) * spd * 0.7;
                s.z = -Math.sin(r) * spd * 0.7;
                this.emit(EventType.LevelEvent.addTrapper, {
                    role: this,
                    speed: s,
                });
                r = this.faceRadian + 0.3;
                s.x = Math.cos(r) * spd;
                s.z = -Math.sin(r) * spd;
                this.emit(EventType.LevelEvent.addTrapper, {
                    role: this,
                    speed: s,
                });
                r = this.faceRadian - 0.3;
                s.x = Math.cos(r) * spd;
                s.z = -Math.sin(r) * spd;
                this.emit(EventType.LevelEvent.addTrapper, {
                    role: this,
                    speed: s,
                });
                break;
            }

        }
    }

    /**胜利后得瑟 */
    protected stepWin(dt: number) {
        // //转向
        // if (this.faceRadian !== this.targetRadian) {
        //     let step = Math.PI * dt * 3;
        //     if (step > Math.abs(this.targetRadian - this.faceRadian)) {
        //         this.faceRadian = this.targetRadian;
        //     } else {
        //         if (!this.trunLeft) {
        //             step = -step;
        //         }
        //         this.faceRadian += step;
        //     }
        //     let r = this.faceRadian * 0.5;
        //     this.node.setRotation(0, Math.sin(r), 0, Math.cos(r));
        // }
        this.updateInvicible(dt);
        this.updateMatUniform(dt);
    }

    protected nextPortalPos: Vec3 = v3();
    protected stepPortal(dt: number) {
        this.cachePos.x += this.speed.x * dt;
        this.cachePos.z += this.speed.z * dt;
        if (Math.abs(this.cachePos.x - this.nextPortalPos.x) < 0.1
            && Math.abs(this.cachePos.z - this.nextPortalPos.z) < 0.1) {
            this.jumpOutPortal(this.nextPortalPos);
        } else {
            this.node.setPosition(this.cachePos);
        }
    }
}
